﻿//========================================================= 
/**@file LogCat.h
 * @brief 对日志的应用层接口封装
 *
 * - ILogAppender接口进行日志输出,参数中带tag,可在更下层进行适配对接log4cpp等其他日志框架
 * - ILogLayout接口提供输出格式控制,每行日志均计算一次
 * - ILogFollower进行日志输出调用方式的控制,每行日志产生一个临时变量,析构时调用ILogLayout和ILogAppender进行输出
 * - LogCat为日志输出的主要控制器,使用Tag进行标识,负责提供debug(),error()等接口返回日志操作的ILogFollower临时对象
 * - LogCatManager为LogCat的工厂,负责管理ILogAppender和ILogLayout,通过Get方法返回指定名称的特定设置的LogCat用于日志输出
 * - LogCatManager仅提供ILogAppender全局统一的输出级别控制,细化的输出级别控制通过其他辅助类完成
 * 
 * - LogExtension::LogLv提供了可细化的输出级别控制,不同ILogAppender可输出不同的级别
 * - LogExtension::LogAsync提供带锁的日志控制
 * - LogExtension::LogCached提供带缓存的日志控制
 * .
 * 
 * @date 2018-06-14   19:52:15
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_LOGCAT_H_
#define _LIBZHOUYB_LOGCAT_H_
//--------------------------------------------------------- 
#include "ILogCat.h"

#include "follower/StreamFollower.h"

#include "../ability/ObjectPool.h"
using zhou_yb::extension::ability::RefObjectPool;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace extension {
namespace logcat {
//--------------------------------------------------------- 
class LogPrinter : public ILogAppender, public RefObject
{
public:
    virtual void append(LogLevel lv, const char* tag, const char* str)
    {
        // 日志级别限制不需要做输出
        if(lv < Lv)
            return;
        if(Appender.IsNull())
            return;
        if(Layout.IsNull())
        {
            Appender->append(lv, tag, str);
            return;
        }
        const char* ptr = str;
        string msg;
        Layout->message(lv, tag, msg);
        if(msg.length() > 0)
        {
            msg += _strput(str);
            ptr = msg.c_str();
        }
        Appender->append(lv, tag, ptr);
    }

    Ref<ILogAppender> Appender;
    Ref<ILogLayout> Layout;
    LogLevel Lv;

    LogPrinter() : Appender(), Layout(), Lv(LogAll) {}
};
//--------------------------------------------------------- 
/**
 * @brief 空的Layout
 * @date 2018-12-13 16:19:30
 */
class NullLayout : public ILogLayout, public RefObject
{
public:
    virtual size_t message(LogLevel lv, const char* tag, string& msg) { msg = ""; return 0; }
};
//--------------------------------------------------------- 
/**
 * @brief 支持带TAG标签的日志
 * @date 2018-06-19 18:35:54
 */
class LogCat
{
public:
    /// 追随器类型
    typedef StreamFollower FollowerType;
public:
    /// 根据宏生成当前LogCat的TAG
    static string MacroTAG(const char* file, const char* func)
    {
        ByteBuilder tag(8);
        ByteArray buff(file);
        size_t index = StringConvert::LastIndexOf(buff, PATH_SEPARATOR);
        tag.Append(buff.SubArray(index + 1));

        // 过滤命名空间
        ByteArray spaceFlags("::");
        buff = ByteArray(func);

        ByteArray tmp(buff);
        index = StringConvert::LastIndexOf(tmp, spaceFlags);
        if(index != SIZE_EOF)
        {
            tmp = buff.SubArray(0, index);
            index = StringConvert::LastIndexOf(tmp, spaceFlags);
            if(index != SIZE_EOF)
            {
                buff = buff.SubArray(index + spaceFlags.GetLength());
            }
        }
        if(buff.GetLength() > 0)
        {
            tag.Append(":");
            tag.Append(buff);
        }
        return tag.GetString();
    }
    /// 将字符串格式的日志级别转为枚举类型
    static LogLevel ConvertFrom(const char* s_lv)
    {
        ByteArray lv_msg(s_lv);
        if (StringConvert::Compare(lv_msg, "DEBUG", true))
        {
            return LogDebug;
        }
        else if (StringConvert::Compare(lv_msg, "INFO", true))
        {
            return LogInfo;
        }
        else if (StringConvert::Compare(lv_msg, "WARN", true))
        {
            return LogWarning;
        }
        else if (StringConvert::Compare(lv_msg, "ERROR", true))
        {
            return LogError;
        }
        else if (StringConvert::Compare(lv_msg, "FATAL", true))
        {
            return LogFatal;
        }
        else if (StringConvert::Compare(lv_msg, "TRACE", true))
        {
            return LogTrace;
        }
        else if (StringConvert::Compare(lv_msg, "ALL", true))
        {
            return LogAll;
        }
        return LogOff;
    }
    /// 将日志级别转为对应的字符串格式
    static const char* ConvertTo(LogLevel lv)
    {
        switch(lv)
        {
        case LogAll:
            return "ALL";
        case LogTrace:
            return "TRACE";
        case LogDebug:
            return "DEBUG";
        case LogInfo:
            return "INFO";
        case LogWarning:
            return "WARN";
        case LogError:
            return "ERROR";
        case LogFatal:
            return "FATAL";
        case LogOff:
            break;
        }
        return "LogOff";
    }
protected:
    string _tag;
    Ref<LogPrinter> _appender;
public:
    LogCat(const string& tag = "", 
        Ref<LogPrinter> appender = Ref<LogPrinter>()) :
        _tag(tag), _appender(appender) {}

    /// 返回指定类型的日志跟随器(析构时自动输出日志)
    template<class TFollower>
    TFollower Get(LogLevel lv)
    {
        // 日志级别限制不需要做输出
        if(_appender.IsNull() || _appender->Lv > lv)
            return TFollower();

        const char* sTag = _tag.c_str();
        TFollower follower(_appender, lv, sTag);
        return follower;
    }

    inline FollowerType message(LogLevel lv)
    {
        return Get<FollowerType>(lv);
    }
    inline FollowerType trace()
    {
        return message(LogTrace);
    }
    inline FollowerType debug()
    {
        return message(LogDebug);
    }
    inline FollowerType info()
    {
        return message(LogInfo);
    }
    inline FollowerType warn()
    {
        return message(LogWarning);
    }
    inline FollowerType error()
    {
        return message(LogError);
    }
    inline FollowerType fatal()
    {
        return message(LogFatal);
    }
};
//--------------------------------------------------------- 
/// 日志对象
class LogCatLogger
{
protected:
    RefObjectPool<ILogAppender> _appenders;
    RefObjectPool<ILogLayout> _layouts;
    MapArguments<string, LogPrinter> _printers;
public:
    virtual ~LogCatLogger()
    {
        Clean();
    }
    /// 返回一个指定名称的Layout,没有则新建
    template<class T>
    Ref<T> NewLayout(const string& name)
    {
        return _layouts.CreateObject<T>(name);
    }
    /// 返回指定名称的Layout
    inline Ref<ILogLayout> Layout(const string& name)
    {
        return _layouts.Get(name);
    }
    /// 返回一个指定名称的Appender,没有则新建
    template<class T>
    Ref<LogPrinter> NewAppender(const string& name, Ref<T>& appender,
        Ref<ILogLayout> layout = Ref<ILogLayout>(), LogLevel lv = LogAll)
    {
        LogPrinter& p = _printers.Put(name);
        appender = _appenders.CreateObject<T>(name);
        p.Appender = appender;
        p.Layout = layout;
        p.Lv = lv;
        return p;
    }
    template<class T>
    Ref<LogPrinter> NewAppender(const string& name, Ref<ILogLayout> layout = Ref<ILogLayout>(), LogLevel lv = LogAll)
    {
        Ref<T> appender;
        return NewAppender<T>(name, appender, layout, lv);
    }
    /// 返回指定名称的Printer
    inline Ref<ILogAppender> Appender(const string& name)
    {
        return _appenders.Get(name);
    }
    /// 设置指定日志的输出级别
    LogLevel SetPriority(const string& name, LogLevel lv)
    {
        LogPrinter& p = _printers[name].Value;
        LogLevel oldLv = p.Lv;
        p.Lv = lv;
        return oldLv;
    }
    /// 清空
    void Clean()
    {
        _appenders.Clean();
        _layouts.Clean();
        _printers.Clear();
    }
    /// 返回是否为空
    inline bool IsEmpty() const
    {
        return _appenders.Count() < 1;
    }
    /// 返回对应的日志记录器
    LogCat Get(const string& tag = "", const string& name = "")
    {
        MapArguments<string, LogPrinter>::ArgType& v = _printers[name];
        if(v.Key != name)
            return LogCat();
        return LogCat(tag, v.Value);
    }
};
//--------------------------------------------------------- 
/// 日志管理器
class LogCatManager
{
    DisableObjConsturctCopyBehavior(LogCatManager)
protected:
    static MapArguments<string, LogCatLogger> _pool;
public:
    /// 获取指定ID的实例
    static LogCatLogger& Instance(const string& id)
    {
        MapArguments<string, LogCatLogger>::EnumeratorType enumer = _pool.GetEnumerator();
        while(enumer.MoveNext())
        {
            if(enumer.Current().Key == id)
                return enumer.Current().Value;
        }
        return _pool.Put(id);
    }
    /// 结束实例
    inline static bool Shutdown(const string& id)
    {
        return _pool.Remove(id);
    }
    /// 结束所有实例
    inline static void Shutdown()
    {
        _pool.Clear();
    }
};
//--------------------------------------------------------- 
} // namespace logcat
} // namespace extension
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_LOGCAT_H_
//========================================================= 